//package com.tianji.promotion.service.impl;
//
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.tianji.common.domain.dto.PageDTO;
//import com.tianji.common.exceptions.BadRequestException;
//import com.tianji.common.exceptions.BizIllegalException;
//import com.tianji.common.utils.BeanUtils;
//import com.tianji.common.utils.CollUtils;
//import com.tianji.common.utils.StringUtils;
//import com.tianji.common.utils.UserContext;
//import com.tianji.promotion.domain.po.Coupon;
//import com.tianji.promotion.domain.po.ExchangeCode;
//import com.tianji.promotion.domain.po.UserCoupon;
//import com.tianji.promotion.domain.query.CouponQuery;
//import com.tianji.promotion.domain.vo.CouponVO;
//import com.tianji.promotion.enums.ExchangeCodeStatus;
//import com.tianji.promotion.enums.MyLockStrategy;
//import com.tianji.promotion.mapper.CouponMapper;
//import com.tianji.promotion.mapper.UserCouponMapper;
//import com.tianji.promotion.service.IExchangeCodeService;
//import com.tianji.promotion.service.IUserCouponService;
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.tianji.promotion.utils.CodeUtil;
//import com.tianji.promotion.annotations.MyLock;
//import com.tianji.promotion.enums.MyLockType;
//import lombok.RequiredArgsConstructor;
//import org.redisson.api.RedissonClient;
//import org.springframework.aop.framework.AopContext;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.time.LocalDateTime;
//import java.util.ArrayList;
//import java.util.Arrays;
//import java.util.HashMap;
//import java.util.HashSet;
//import java.util.List;
//import java.util.Map;
//import java.util.Set;
//import java.util.stream.Collectors;
//
///**
// * <p>
// * 用户领取优惠券的记录，是真正使用的优惠券信息 服务实现类
// * </p>
// *
// * @author yb0os1
// * @since 2025-03-09
// */
//@Service
//@RequiredArgsConstructor
//public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> implements IUserCouponService {
//    private final CouponMapper couponMapper;
//    private final IExchangeCodeService exchangeCodeService;
//
//    /**
//     * 用户领取优惠券
//     *
//     * @param id 优惠券的di
//     *           注意事项：
//     *           校验信息，比如优惠券是否还有库存、优惠券的领取日期是否开始或者截止、当前用户是否已经领了最大限制的数量
//     */
//    @Override
//    public void receiveCoupon(Long id) {
//        //1、判断优惠券id是否存在
//        if (id == null) {
//            throw new BadRequestException("优惠券id不能为空");
//        }
//        //2、从优惠券的表中根据id查询优惠券
//        Coupon coupon = couponMapper.selectById(id);
//        if (coupon == null) {
//            throw new BadRequestException("优惠券不存在");
//        }
//        //3、判断优惠券是否还有库存、优惠券的领取日期是否开始或者截止
//        if (coupon.getIssueNum() >= coupon.getTotalNum()) {
//            throw new BadRequestException("优惠券已领完");
//        }
//        LocalDateTime now = LocalDateTime.now();
//        if (coupon.getIssueBeginTime().isAfter(now) || coupon.getIssueEndTime().isBefore(now)) {
//            throw new BadRequestException("优惠券还未开始或已经结束");
//        }
//        //4、判断当前用户是否已经领了最大限制的数量
//        Long userId = UserContext.getUser();
//        //5、优惠券表已领取的数量+1
//        //6、用户优惠券表插入一条记录
//        IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();
//        //默认直接写方法执行是调用的原对象的方法，而不是代理对象的方法  我们事务是基于AOP 代理对象来执行事务的
//        userCouponServiceProxy.checkAndSaveUserCoupon(coupon, userId, null);
//
//    }
//
//    /**
//     * 兑换码兑换优惠券
//     *
//     * @param code 兑换码
//     *             <p>
//     *             注意 需要校验兑换码和优惠券的信息
//     *             兑换码格式
//     *             兑换码是否已经兑换
//     *             兑换码是否存在
//     *             兑换码是否过期
//     *             每个人限领数量
//     */
//    @Override
//    public void codeExchangeCoupon(String code) {
//        //1、兑换码是否为空
//        if (StringUtils.isBlank(code)) {
//            throw new BadRequestException("兑换码不能为空");
//        }
//        //2、检验兑换码的格式并且解析兑换码  解析出来就是 自增id
//        long serialNum = CodeUtil.parseCode(code);
//        //3、查询兑换码否已经兑换 查之前并且更新
//        boolean exchanged = exchangeCodeService.updateExchangeMark(serialNum, true);
//        if (exchanged) {
//            throw new BadRequestException("兑换码已经兑换");
//        }
//        try {
//            //4、兑换码是否存在
//            ExchangeCode exchangeCode = exchangeCodeService.getById(serialNum);
//            if (exchangeCode == null) {
//                throw new BadRequestException("兑换码不存在");
//            }
//            //5、兑换码是否过期
//            LocalDateTime now = LocalDateTime.now();
//            if (!exchangeCode.getExpiredTime().isAfter(now)) {
//                throw new BadRequestException("兑换码已经过期");
//            }
//            //6、是否超过用户限领数量
//            //7、优惠券已发放数量+1
//            //8、用户优惠券表插入一条记录
//            //9、更新兑换码状态
//            Coupon coupon = couponMapper.selectById(exchangeCode.getExchangeTargetId());
//            IUserCouponService o = (IUserCouponService) AopContext.currentProxy();
//            o.checkAndSaveUserCoupon(coupon, UserContext.getUser(), serialNum);
//        } catch (Exception e) {
//            //出现异常状态的话就要重置兑换码的状态
//            exchangeCodeService.updateExchangeMark(serialNum, false);
//            throw (e);
//        }
//    }
//
//    @Transactional
//    @MyLock(name = "lock:coupon：#{T(com.tianji.common.utils.UserContext).getUser()}", lockType = MyLockType.RE_ENTRANT_LOCK, strategy = MyLockStrategy.FAIL_AFTER_RETRY_TIMEOUT)
//    public void checkAndSaveUserCoupon(Coupon coupon, Long userId, Long serialNum) {
//        /*
//        Long 不可以作为 锁的，因为超过-128-127 Long不会自动装箱了  比较的就是地址
//        String也不可以直接作为锁 toString本质还是new新的对象
//        intern就是强制从常量池中读取字符串 可以作为锁
//         */
//        Long id = coupon.getId();
//        // 1、判断当前用户是否已经领了最大限制的数量
//        Integer userIssuedNums = lambdaQuery()
//                .eq(UserCoupon::getUserId, userId)
//                .eq(UserCoupon::getCouponId, id).count();
//
//        if (userIssuedNums != null && userIssuedNums >= coupon.getUserLimit()) {
//            throw new BadRequestException("当前优惠券用户已领到限领数量");
//        }
//
//        // 2、优惠券表已领取的数量+1
//        boolean isFinish = couponMapper.updateCouponIssueById(id);
//        if (!isFinish) {
//            throw new BadRequestException("优惠券已领完");
//        }
//        //3、用户优惠券表插入一条记录
//        // 1.基本信息
//        UserCoupon userCoupon = new UserCoupon();
//        userCoupon.setUserId(userId);
//        userCoupon.setCouponId(id);
//        // 2.有效期信息
//        if (coupon.getTermDays() == null || coupon.getTermDays() == 0) {
//            userCoupon.setTermBeginTime(coupon.getTermBeginTime());
//            userCoupon.setTermEndTime(coupon.getTermEndTime());
//        } else {
//            userCoupon.setTermBeginTime(LocalDateTime.now());
//            userCoupon.setTermEndTime(LocalDateTime.now().plusDays(coupon.getTermDays()));
//        }
//        // 3.保存到用户优惠券
//        save(userCoupon);
//
//        //4、对于兑换码的优惠券 需要在优惠券表中更改信息
//        if (serialNum != null) {
//            //修改信息 status userId
//            boolean success = exchangeCodeService.lambdaUpdate()
//                    .eq(ExchangeCode::getId, serialNum)
//                    .set(ExchangeCode::getStatus, ExchangeCodeStatus.USED)
//                    .set(ExchangeCode::getUserId, userId)
//                    .update();
//            if (!success) {
//                throw new BizIllegalException("兑换码兑换优惠券失败");
//            }
//        }
//    }
//
//    /**
//     * 查询我的优惠券
//     * @param query 分页参数 状态 名字等
//     * @return
//     */
//    @Override
//    public PageDTO<CouponVO> queryMyCoupons(CouponQuery query) {
//        //1、校验传入的参数
//        if (query==null){
//            throw new BizIllegalException("参数不能为空");
//        }
//        //2、根据传入的条件分页查询 主要仅仅是获得优惠券的id
//        Page<UserCoupon> page = lambdaQuery()
//                .eq(query.getStatus() != null, UserCoupon::getStatus, query.getStatus())
//                .page(query.toMpPageDefaultSortByCreateTimeDesc());
//        List<UserCoupon> records = page.getRecords();
//        if (CollUtils.isEmpty(records)){
//            return PageDTO.empty(page);
//        }
//        //3、将优惠券的id组成set集合
//        Set<Long> ids = records.stream().map(UserCoupon::getCouponId).collect(Collectors.toSet());
//        //4、从coupon优惠券表中查找优惠券信息
//        List<Coupon> coupons = couponMapper.selectBatchIds(ids);
//        List<CouponVO> couponVOS = BeanUtils.copyToList(coupons, CouponVO.class);
//        // 4、返回分页数据
//        return PageDTO.of(page, couponVOS);
//    }
//
//}
//
